/*
Copyright (c) 2009, Luke Berndt
All rights reserved.
 
 * More Information: http://www.tagflo.com

Redistribution and use in source and binary forms, with or without modification, are permitted 
provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions 
  and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of conditions 
  and the following disclaimer in the documentation and/or other materials provided with the distribution.

* Neither the name of RoboTastic Software nor the names of its contributors may be used to endorse or 
  promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/


using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Data.Linq;
using System.Data.EntityClient;
using System.Windows.Shapes;
using System.Data.SqlServerCe;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.Data;
using System.IO;
using System.Threading;
using System.Windows.Threading;
using System.ComponentModel;
using System.Diagnostics;
using Bindable;
using Bindable.Linq;

/*
Copyright (c) 2009, Luke Berndt
All rights reserved.
 
 * More Information: http://www.tagflo.com

Redistribution and use in source and binary forms, with or without modification, are permitted 
provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions 
  and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of conditions 
  and the following disclaimer in the documentation and/or other materials provided with the distribution.

* Neither the name of RoboTastic Software nor the names of its contributors may be used to endorse or 
  promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/


namespace TagFlo
{

    #region TagSetButtonClass

    public class TagSetButton
    {
        private string functionKey;
        private string text;

        public TagSetButton(string t, string f)
        {
            text = t;
            functionKey = f;
        }

        public string Text
        {
            get { return text; }
            set { text = value; }
        }

        public string FunctionKey
        {
            get { return functionKey; }
            set { functionKey = value; }
        }

    }
    #endregion
    #region TagSetListClass
    public class TagSetList : ObservableCollection<TagSetButton>
    {
        public TagSetList()
            : base()
        {
        }
        public void Add(string text, string functionKey)
        {
            base.Add(new TagSetButton(text, functionKey));
        }
    }
    #endregion


    public class PhotoCollectionOrderBy : INotifyPropertyChanged
    {
        private string _OrderBy;
        public string OrderBy
        {
            get
            {
                return _OrderBy;
            }

            set
            {
                _OrderBy = value;
               NotifyChanged("OrderBy");
            }
        }
        private void NotifyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
  
    }
  
   
    #region MainWindowClass
    public partial class MainWindow : System.Windows.Window
    {

        #region MainWindow
        private delegate void NoArgEventDelegate();

        
        public RoutedUICommand FunctionKeyAddTagCommand;
        InputBinding[] tagInputBindings = new InputBinding[12];
        Configuration config;
        ToggleButton[] buttonStars = new ToggleButton[5];
        TagSetList tagSetList;
        Stream logFile;
        PhotoFilter photoFilter; 

        public PhotoDBEntities photoEntities;
        public ThreadedObservableCollection<Photo> photoCollection;
        public ThreadedObservableCollection<Path> pathCollection;
        public ThreadedObservableCollection<Tag> tagCollection;
        public ThreadedObservableCollection<PhotoSet> photoSetCollection;
        public ThreadedObservableCollection<SmartSet> smartSetCollection;

        public static RoutedCommand AddTagCommand = new RoutedCommand();
        public static RoutedCommand RemoveTagCommand = new RoutedCommand();


        StatusWorker statusWorker;
        MetaDataWorker metaDataWorker;
        public ImportWorker importWorker;
        ExportWorker exportWorker;

        Thread statusThread;
        Thread metaDataThread;
        Thread importThread;
        Thread exportThread;
        PhotoCollectionOrderBy orderBy;
        

        public void UpdateTags()
        {
            TagSelectionTreeView_Build();
        }

     
        public void UpdateSelectTree()
        {
             PhotoSelectionPanel.SelectTreeView_Update();
        }

        private void ExecutedAddTagCommand(object sender,  ExecutedRoutedEventArgs e)
        {
            AddTag(e.Parameter.ToString());
        }
        private void ExecutedRemoveTagCommand(object sender, ExecutedRoutedEventArgs e)
        {
            RemoveTag(e.Parameter.ToString());
        }
        private void CanExecuteTagCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            
            if (PhotoListBox.SelectedItems.Count > 0)
            {
                e.CanExecute = true;
            }
            else
            {
                e.CanExecute = false;
            }
        }

        public void AddExportErrorUpdate(string text)
        {
            //byte[] ba2 = (byte[]) ba.Clone();
            StatusItem item = new StatusItem(StatusUpdateType.exportError, text);
            statusWorker.AddStatusUpdate(item);
        }

        public void AddExportUpdate(string text, byte[] ba)
        {
            //byte[] ba2 = (byte[]) ba.Clone();
            StatusItem item = new StatusItem(StatusUpdateType.exportFile, text, ba);
            statusWorker.AddStatusUpdate(item);
        }


        public void AddFileUpdate(string text, byte[] ba)
        {
            //byte[] ba2 = (byte[]) ba.Clone();
            StatusItem item = new StatusItem(StatusUpdateType.addFile, text, ba);
            statusWorker.AddStatusUpdate(item);
        }
       


        public MainWindow()
        {
            logFile = File.Create("LogFile.txt");

            /* Create a new text writer using the output stream, and add it to
             * the trace listeners. */
            TextWriterTraceListener myTextListener = new TextWriterTraceListener(logFile);
            Trace.Listeners.Add(myTextListener);




         
            photoEntities = new PhotoDBEntities();
            
          
            photoCollection = new ThreadedObservableCollection<Photo>(this.Dispatcher, photoEntities.Photos.Include("Tags").Include("PhotoSets").OrderBy(p=>p.DateTaken).ToList());
            tagCollection = new ThreadedObservableCollection<Tag>(this.Dispatcher, photoEntities.Tags.ToList());
            photoSetCollection = new ThreadedObservableCollection<PhotoSet>(this.Dispatcher, photoEntities.PhotoSets.Include("Photos").ToList());
            pathCollection = new ThreadedObservableCollection<Path>(this.Dispatcher, photoEntities.Paths.ToList());
            smartSetCollection = new ThreadedObservableCollection<SmartSet>(this.Dispatcher, photoEntities.SmartSets.ToList());

            photoFilter = new PhotoFilter(this);
            InitializeComponent();
            orderBy = (PhotoCollectionOrderBy)PhotoListBox.FindResource("PhotoCollectionOrderBy");
            PhotoListBox.DataContext = photoCollection;
            //photoCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(PhotoChangeHandler);
            }

/*
        public void PhotoChangeHandler(
    Object sender,
    NotifyCollectionChangedEventArgs e)
        {
            string s = e.Action.ToString();

        }
        */
        private void OnInit(object sender, EventArgs e)
        {
            if (File.Exists("config.xml"))
            {
                config = Configuration.Load("config.xml");
            }
            else
            {
                config = new Configuration();
              
            }


            FunctionKeyAddTagCommand = new RoutedUICommand("Function Key Add Tag...", "FunctionKeyAddTagCommand", typeof(MainWindow));
            CommandBinding FunctionKeyAddTagCommandBinding = new CommandBinding(FunctionKeyAddTagCommand, FunctionKeyAddTag);
            this.CommandBindings.Add(FunctionKeyAddTagCommandBinding);
            BuildFunctionKeyInputBindings();


            metaDataWorker = new MetaDataWorker(this);
            metaDataThread = new Thread(new ThreadStart(metaDataWorker.DoWork));
            metaDataThread.Name = "MetaDataWorker";
            metaDataThread.SetApartmentState(ApartmentState.STA);

            metaDataThread.Start();
            while (!metaDataThread.IsAlive) ;

            metaDataWorker.TagsChanged += new EventHandler(TagChangeHandler);


            importWorker = new ImportWorker(this);
            importThread = new Thread(new ThreadStart(importWorker.DoWork));
            importThread.Name = "ImportThread";
            importThread.Start();
            while (!importThread.IsAlive) ;

            importWorker.DirectoryChanged += new EventHandler(DirectoryChangeHandler);
            importWorker.FileChanged += new EventHandler(FileChangeHandler);


            statusWorker = new StatusWorker(this);
            statusThread = new Thread(new ThreadStart(statusWorker.UpdateStatusThread));
            statusThread.Name = "StatusThread";
            statusThread.Start();
            while (!statusThread.IsAlive);

            exportWorker = new ExportWorker(this, config);
            exportThread = new Thread(new ThreadStart(exportWorker.UpdateExportThread));
            exportThread.Name = "StatusThread";
            exportThread.Start();
            while (!exportThread.IsAlive) ;

            //bindingView = (BindingListCollectionView)CollectionViewSource.GetDefaultView(sqlDataSet.dataSet.Tables["PhotoTable"]);
            //sqlDataSet.dataSet;


            ButtonStars_Create();

            TagComboBox.IsEditable = true;
            TagComboBox.StaysOpenOnEdit = true;
            //TagComboBox.IsTextSearchEnabled = true;
            TagComboBox.ItemsSource = from t in tagCollection select t.TagName;
           // TagListBox.ItemsSource = from t in tagCollection select t.TagName;
            //TagComboBox.DataContext = sqlDataSet.dataSet;
            //DateTreeViewItem.Selected += new RoutedEventHandler(SelectTreeView_DateItemSelected);
           //    TagComboBoxTextBox = TagComboBox.Template.FindName("PART_EditableTextBox", TagComboBox) as TextBox;
              
         //   TagComboBoxTextBox.PreviewKeyDown += new KeyEventHandler(TagComboBoxTextBox_PreviewKeyDown);
            StackPanel panel = TagComboBox.Template.FindName("PART_ItemList", TagComboBox) as StackPanel;
            panel.PreviewKeyDown += new KeyEventHandler(TagComboBoxTextBox_PreviewKeyDown);
            ContentPresenter presenter = TagComboBox.Template.FindName("ContentSite", TagComboBox) as ContentPresenter;
            presenter.PreviewKeyDown += new KeyEventHandler(TagComboBoxTextBox_PreviewKeyDown);
            
            PhotoSelectionPanel.SelectTreeView_Build(this); 
            tagSetList = new TagSetList();
            TagSetListView.DataContext = tagSetList;
            TagSetComboBox.DataContext = photoEntities.TagSets.Include("Tags");


            //PhotoSetListBox.SqlDataSet = sqlDataSet;
            PhotoSetListBox.PhotoCollection = photoCollection;
            PhotoSetListBox.PhotoSetCollection = photoSetCollection;
           
  


        }

        private void OnClose(object sender, EventArgs e)
        {
            Trace.WriteLine("Closing threads");
            metaDataThread.Abort();
            importThread.Abort();
            statusThread.Abort();
            exportThread.Abort();

            importThread.Join();
            metaDataThread.Join();
            statusThread.Join();
            exportThread.Join();
            Trace.WriteLine("Threads Closed!");

            // Flush the output.
            Trace.Flush();

        }

        private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
            if (elementWithFocus.GetType() != typeof(TextBox))
            {

                KeyEventArgs keyEvent = new KeyEventArgs(e.KeyboardDevice, Keyboard.PrimaryDevice.ActiveSource, 0, e.Key);
                keyEvent.RoutedEvent = Keyboard.PreviewKeyDownEvent;
                PhotoListBox.RaiseEvent(keyEvent);
            }
        }
        #endregion


        #region Menu
        private void MenuImport_Click(object sender, RoutedEventArgs e)
        {
            //PhotoListBox.SelectedItem = null; // we need to set this to null, 
            ImportDialog importDialog = new ImportDialog(this);
            importDialog.ShowDialog();
            // importWorker.AddScan();
        }

        private void MenuSettings_Click(object sender, RoutedEventArgs e)
        {
            //PhotoListBox.SelectedItem = null; // we need to set this to null, 
            SettingsDialog settingsDialog = new SettingsDialog(config);
            settingsDialog.ShowDialog();
            Configuration.Save("config.xml", config);
            exportWorker.UpdateExport();
            // importWorker.AddScan();
        }

        private void MenuAbout_Click(object sender, RoutedEventArgs e)
        {
            //PhotoListBox.SelectedItem = null; // we need to set this to null, 
            AboutDialog aboutDialog = new AboutDialog();
            aboutDialog.ShowDialog();
            // importWorker.AddScan();
        }

        private void MenuHelp_Click(object sender, RoutedEventArgs e)
        {
            //string path = Application.StartupPath;
           // string path = AppDomain.CurrentDomain.BaseDirectory;
           // System.Diagnostics.Process.Start(path + "TagFlo.chm");
            System.Diagnostics.Process.Start("http://www.tagflo.com/help");
   
        }
        #endregion

        #region SelectTreeView
        private void PhotoSelectionPanel_FilterChanged(object sender, RoutedEventArgs e)
        {   
            PhotoListBox.SelectedItem = null;

            if (PhotoSelectionPanel.Filters.Count > 0)
            {
                photoFilter.filters = PhotoSelectionPanel.Filters;
                List<Photo> tempList = photoFilter.FilterCollection();
                if (tempList != null)
                {
                    PhotoListBox.ItemsSource = new ThreadedObservableCollection<Photo>(this.Dispatcher, tempList);
                }
            }
            else
            {
                PhotoListBox.ItemsSource = photoCollection;

            }
           
        }
        #endregion

        void SmartSetButton_Click(object sender, RoutedEventArgs e)
        {
            SmartSetDialog smartSetDialog = new SmartSetDialog(photoEntities);
            smartSetDialog.ShowDialog();
            PhotoSelectionPanel.SmartSetItem_Update();

        }

        void PhotoSetListBox_PhotoSetChange(object sender, RoutedEventArgs e)
        {
            PhotoSelectionPanel.PhotoSetItem_Update();
        }

        private void SelectListView_TagItemClick(object sender, RoutedEventArgs e)
        {
            System.Windows.Controls.Button b = (sender as System.Windows.Controls.Button);
            TextBlock t = (b.Content as TextBlock);
            AddTag(t.Text);

        }
        void TagSelectionTreeView_Build()
        {
            if (PhotoListBox.SelectedItems.Count > 0)
            {
           
                //List<Tag> tags = new List<Tag>();
                List<int> photoIds = new List<int>();

                foreach (object o in PhotoListBox.SelectedItems)
                {
                    if (o.GetType() == typeof(Photo))
                    {
                        Photo photo = (Photo)o;
                        //tags.AddRange(photo.Tags);
                        photoIds.Add(photo.PhotoID);
                    }
                }

                var tags = (from p in photoCollection.AsBindable() where photoIds.Contains(p.PhotoID) from t in p.Tags select t).Distinct();
                TagSelectionTreeView.ItemsSource = tags;
                Trace.WriteLine("Assigned style to all the rows: " + DateTime.Now.TimeOfDay.ToString());
           
            }

        }

        void SelectionTreeUpdater()
        {
            PhotoSelectionPanel.SelectTreeView_Update();

        }
        private void FileChangeHandler(object sender, EventArgs e)
        {

//            NoArgEventDelegate selectionTreeUpdater = new NoArgEventDelegate(SelectionTreeUpdater);
  //          this.Dispatcher.BeginInvoke(DispatcherPriority.Send, selectionTreeUpdater);


            //  TagSelectionTreeView_Build();
        }

        private void DirectoryChangeHandler(object sender, EventArgs e)
        {

            NoArgEventDelegate selectionTreeUpdater = new NoArgEventDelegate(SelectionTreeUpdater);
            this.Dispatcher.BeginInvoke(DispatcherPriority.Send, selectionTreeUpdater);


            //  TagSelectionTreeView_Build();
        }
        private void TagChangeHandler(object sender, EventArgs e)
        {

            NoArgEventDelegate tagUpdater = new NoArgEventDelegate(TagSelectionTreeView_Build);
            this.Dispatcher.BeginInvoke(DispatcherPriority.Send, tagUpdater);
                  

          //  TagSelectionTreeView_Build();
        }

        #region PhotoListBox


        private T GetObjectOfTypeInVisualTree<T>(DependencyObject dpob) where T : DependencyObject
        {
            int count = VisualTreeHelper.GetChildrenCount(dpob);
            for (int i = 0; i < count; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(dpob, i);
                T childAsT = child as T;
                if (childAsT != null)
                {
                    return childAsT;
                }
                childAsT = GetObjectOfTypeInVisualTree<T>(child);
                if (childAsT != null)
                {
                    return childAsT;
                }
            }
            return null;
        }

        public void PhotoSortComboBox_SelectionChanged(Object sender, SelectionChangedEventArgs e)
        {
            if (PhotoListBox != null)
            {
                 switch (PhotoSortComboBox.SelectedIndex)
                {
                    case 0:
                        photoCollection = new ThreadedObservableCollection<Photo>(this.Dispatcher, photoEntities.Photos.Include("Tags").Include("PhotoSets").OrderBy(p => p.DateTaken).ToList());
            
                        PhotoListBox.DataContext = photoCollection;
                       orderBy.OrderBy = "Date";
                         break;
                    case 1:
                         photoCollection = new ThreadedObservableCollection<Photo>(this.Dispatcher, photoEntities.Photos.Include("Tags").Include("PhotoSets").OrderBy(p => p.Rating).ToList());
            
                         PhotoListBox.DataContext = photoCollection;
                         
                       orderBy.OrderBy = "Rating";
                        break;
                    case 2:
                        photoCollection = new ThreadedObservableCollection<Photo>(this.Dispatcher, photoEntities.Photos.Include("Tags").Include("PhotoSets").OrderBy(p => p.IsoSpeed).ToList());
            
                        PhotoListBox.DataContext = photoCollection;
                       orderBy.OrderBy = "IsoSpeed";
                   break;
                    case 3:
                   photoCollection = new ThreadedObservableCollection<Photo>(this.Dispatcher, photoEntities.Photos.Include("Tags").Include("PhotoSets").OrderBy(p => p.ExposureTime).ToList());
            
                        PhotoListBox.DataContext = photoCollection;
                       orderBy.OrderBy = "ExposureTime";
               
                        break;
                    case 4:
                        photoCollection = new ThreadedObservableCollection<Photo>(this.Dispatcher, photoEntities.Photos.Include("Tags").Include("PhotoSets").OrderBy(p => p.FocalLength).ToList());
            
                        PhotoListBox.DataContext = photoCollection;
                       orderBy.OrderBy = "FocalLength";
                     break;
                    case 5:
                     photoCollection = new ThreadedObservableCollection<Photo>(this.Dispatcher, photoEntities.Photos.Include("Tags").Include("PhotoSets").OrderBy(p => p.LensAperture).ToList());
            
                        PhotoListBox.DataContext = photoCollection;
                       orderBy.OrderBy = "LensAperture";
                     break;
                    case 6:
                     photoCollection = new ThreadedObservableCollection<Photo>(this.Dispatcher, photoEntities.Photos.Include("Tags").Include("PhotoSets").OrderBy(p => p.CameraModel).ToList());
            
                     PhotoListBox.DataContext = photoCollection;
                       orderBy.OrderBy = "CameraModel";
                  break;
                    case 7:
                  photoCollection = new ThreadedObservableCollection<Photo>(this.Dispatcher, photoEntities.Photos.Include("Tags").Include("PhotoSets").OrderBy(p => p.Width).ToList());
            
                  PhotoListBox.DataContext = photoCollection;
                       orderBy.OrderBy = "Width";
                   break;
                    case 8:
                   photoCollection = new ThreadedObservableCollection<Photo>(this.Dispatcher, photoEntities.Photos.Include("Tags").Include("PhotoSets").OrderBy(p => p.Height).ToList());
            
                   PhotoListBox.DataContext = photoCollection;
                       orderBy.OrderBy = "Height";
                         break;

                }
                
            }
        }

        private BitmapImage TempImage(byte[] thumbnail)
        {
            MemoryStream mem = new MemoryStream(thumbnail);




            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            /*   if (width > 0)
               {
                   bi.DecodePixelWidth = (int)width;
                   bi.DecodePixelHeight = (int)height;
               }*/
            //bi.UriSource = new Uri(_filename); slow slow slow
            bi.StreamSource = mem;
            bi.EndInit();
            bi.Freeze();

            return bi;

        }
        
        
        public void PhotoListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            ListBoxItem item = ItemsControl.ContainerFromElement(PhotoListBox, e.OriginalSource as DependencyObject) as ListBoxItem;
            if (item != null)
            {

                Photo photo = (Photo)item.Content;
               
                //Image largeImage = (Image)this.Template.FindName("LargeImage", this);
                LargeImageViewer.Visibility = Visibility.Visible;
                Keyboard.Focus(LargeImageViewer);
                LargeImageViewer.LoadImage(photo.FullFilename);
                
                //MessageBox.Show("ListBoxItem is clicked");
            }
            else
            {
                //MessageBox.Show("God knows where is clicked");
            }
        }
        private void LargeImageViewer_NextImage(object sender, RoutedEventArgs e)
        {
            if (PhotoListBox.SelectedIndex < (PhotoListBox.Items.Count - 1))
            {
                PhotoListBox.SelectedIndex++;
                e.Handled = true;

            }
        }
        private void LargeImageViewer_PreviousImage(object sender, RoutedEventArgs e)
        {
            if (PhotoListBox.SelectedIndex > 0)
            {
                PhotoListBox.SelectedIndex--;
                e.Handled = true;

            }
        }
        private void LargeImageViewer_AddImageToPhotoSet(object sender, RoutedEventArgs e)
        {
            foreach (Photo photo in PhotoListBox.SelectedItems)
            {
                PhotoSetListBox.AddImage(photo);
            }
        }

        

        private void LargeImage_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.D0)
            {
                if (PhotoListBox.SelectedIndex > 0)
                {
                    AddRating(0);
                    e.Handled = true;
                }
            }
            if (e.Key == Key.D1)
            {
                if (PhotoListBox.SelectedIndex > 0)
                {
                    AddRating(1);
                    e.Handled = true;
                }
            }
            if (e.Key == Key.D2)
            {
                if (PhotoListBox.SelectedIndex > 0)
                {
                    AddRating(2);
                    e.Handled = true;
                }
            }
            if (e.Key == Key.D3)
            {
                if (PhotoListBox.SelectedIndex > 0)
                {
                    AddRating(3);
                    e.Handled = true;
                }
            }
            if (e.Key == Key.D4)
            {
                if (PhotoListBox.SelectedIndex > 0)
                {
                    AddRating(4);
                    e.Handled = true;
                }
            }
            if (e.Key == Key.D5)
            {
                if (PhotoListBox.SelectedIndex > 0)
                {
                    AddRating(5);
                    e.Handled = true;
                }
            }
            if (e.Key == Key.Left)
            {
                if (PhotoListBox.SelectedIndex > 0)
                {
                    PhotoListBox.SelectedIndex--;
                    e.Handled = true;
             
                }
            }
            if (e.Key == Key.Right)
            {
                if (PhotoListBox.SelectedIndex < (PhotoListBox.Items.Count - 1))
                {
                    PhotoListBox.SelectedIndex++;
                    e.Handled = true;
             
                }
            }

        }


        public void PhotoListBox_SelectionChanged(Object sender, SelectionChangedEventArgs e)
        {
            if (PhotoListBox.SelectedItems.Count > 0)
            {
                CurrentSelectionStackPanel.Visibility = Visibility.Visible;
                if (PhotoListBox.SelectedItems.Count == 1)
                {
                    Photo photo = (Photo)PhotoListBox.SelectedItem;
                    MemoryStream mem = new MemoryStream(photo.Thumbnail.ToArray());

                    BitmapImage img = new BitmapImage();
                    img.BeginInit();
                    img.StreamSource = mem;

                    img.CreateOptions = BitmapCreateOptions.None;

                    img.CacheOption = BitmapCacheOption.Default;

                        
                    img.EndInit();
                        //CurrentSelectionText.Text = drv.Row["Filename"].ToString();
                        CurrentSelectionText.Text = photo.DateTaken.ToString();
                        CurrentSelectionTitleText.Text = photo.Title;
                        CurrentSelectionSubjectText.Text = photo.Subject;
                        CurrentSelectionCommentText.Text = photo.Comment;


                        IsoSpeedConverter isoConverter = new IsoSpeedConverter();
                        CurrentSelectionIsoText.Text = "ISO " + (string) isoConverter.Convert(photo.IsoSpeed) ;

                        FocalLengthConverter focalLengthConverter = new FocalLengthConverter();
                        CurrentSelectionLensText.Text = (focalLengthConverter.Convert(photo.FocalLength) as string);
                   
                        LensApertureConverter apertureConverter = new LensApertureConverter();
                        CurrentSelectionApertureText.Text = (apertureConverter.Convert(photo.LensAperture) as string);

                        ExposureTimeConverter exposureTimeConverter = new ExposureTimeConverter();
                        CurrentSelectionShutterSpeedText.Text = (exposureTimeConverter.Convert(photo.ExposureTime) as string) +" s";
         
                }
                else
                {
                    CurrentSelectionText.Text = PhotoListBox.SelectedItems.Count + " files selected";
                    CurrentSelectionTitleText.Text = "";
                    CurrentSelectionSubjectText.Text = "";
                    CurrentSelectionCommentText.Text = "";
                    CurrentSelectionIsoText.Text = "";
                    CurrentSelectionLensText.Text = "";
                    CurrentSelectionApertureText.Text = "";
                    CurrentSelectionShutterSpeedText.Text = "";
              


                }

                if (LargeImageViewer.Visibility == Visibility.Visible)
                {
                    Photo photo = (Photo) PhotoListBox.SelectedItem;

                    
                    LargeImageViewer.LoadImage(photo.FullFilename);
                }
            }
            else
            {
                CurrentSelectionStackPanel.Visibility = Visibility.Hidden;
            }
            TagSelectionTreeView_Build();
            ButtonStars_Update();
        }

        #endregion



        private void AddTag(String s)
        {
            foreach (Photo photo in PhotoListBox.SelectedItems)
            {
                metaDataWorker.AddWork(photo.PhotoID, "Tag", s);
                statusWorker.AddInformationUpdate("+ Tag: " + s);
                
            }
        }

        private void RemoveTag(String s)
        {
            foreach (Photo photo in PhotoListBox.SelectedItems)
            {
                metaDataWorker.AddWork(photo.PhotoID, "RemoveTag", s);
            }
            statusWorker.AddInformationUpdate("- Tag: " + s);

        }


        #region StatusPopup


        public void LowerStatusPopup()
        {
            if (StatusPopup.IsOpen == true)
            {
                StatusPopup.IsOpen = false;
            }
        }
        public void RaiseStatusPopup(string text, byte[] ba)
        {
            StatusText.Text = text;

            if (ba != null)
            {

                MemoryStream stream = new MemoryStream(ba);

                BitmapImage bi = new BitmapImage();
                bi.BeginInit();
                bi.CacheOption = BitmapCacheOption.OnLoad;
                bi.DecodePixelHeight = 125;
                bi.DecodePixelWidth = 125;
                bi.StreamSource = stream;
                bi.EndInit();
                StatusImage.Source = bi;
                StatusPopup.Height = 150;
                StatusPopup.VerticalOffset = -150;
            }
            else
            {
                StatusPopup.Height = 25;
                StatusPopup.VerticalOffset = -25;
            }

            if (StatusPopup.IsOpen == false)
            {
                StatusPopup.IsOpen = true;
            }

        }
        #endregion


        #region TagSet
        private void TagSetButtonUpdate()
        {
            if (TagSetComboBox.SelectedItem != null)
            {
                if (TagSetComboBox.SelectedItem.GetType() == typeof(TagSet))
                {
                    TagSet tagSet = (TagSet)TagSetComboBox.SelectedItem;
                        tagSetList.Clear();
                        int i = 0;
                        foreach (Tag tag in tagSet.Tags)
                        {
                            string s = tag.TagName;
                            if (s.Length > 0)
                            {
                                string functionKey = "F" + (i + 1).ToString();
                                tagSetList.Add(s, functionKey);
                                tagInputBindings[i].CommandParameter = s;
                                this.InputBindings.Add(tagInputBindings[i]);
                            }
                            else
                            {
                                this.InputBindings.Remove(tagInputBindings[i]);
                            }
                            i++;
                        }
                   
                }
                else
                {
                    tagSetList.Clear();
                    for (int i = 0; i < 12; i++)
                    {
                        this.InputBindings.Remove(tagInputBindings[i]);
                    }
                }
            }
        }
        public void TagSetComboBox_DropDownClosed(object sender, EventArgs e)
        {
            
            TagSetButtonUpdate();

        }

        private void TagSetEditButton_Click(object sender, RoutedEventArgs e)
        {
            TagDialog tagDialog = new TagDialog();
            tagDialog.ShowDialog();
            TagSetComboBox.DataContext = photoEntities.TagSets.Include("Tags");
            TagSetButtonUpdate();
        }

        private void TagSetButton_Click(object sender, RoutedEventArgs e)
        {
            if (sender.GetType() == typeof(System.Windows.Controls.Button))
            {
                System.Windows.Controls.Button b = (System.Windows.Controls.Button)sender;
                TagSetButton tagSetButton = (TagSetButton)b.DataContext;

                string s = tagSetButton.Text;
                AddTag(s);
            }
        }

        #endregion

        #region TagComboBox
/*
        public void TagComboBox_SelectionChanged(Object sender, SelectionChangedEventArgs e)
        {
            if ((e.AddedItems.Count > 0))
            {
                //DataRowView row = (DataRowView)e.AddedItems[0];
                //AddTag(row["PhotoSetName"].ToString());
                //String s = (String)e.AddedItems[0];
                //currentPhotoSetName = s;
           
            }

        }


        public void TagComboBoxTextBox_TextChanged(Object sender, TextChangedEventArgs e)
        {
            if (TagComboBoxTextBox.SelectionLength > 0)
            {
               string unselectedText = TagComboBoxTextBox.Text.Substring(0, TagComboBoxTextBox.SelectionStart);
                
                    sqlDataSet.SelectDistinctTagTable(unselectedText);
                
            }
            else
            {
                sqlDataSet.SelectDistinctTagTable(TagComboBoxTextBox.Text);
            }
        }
*/
        
        public void TagComboBoxTextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            
            if (e.Key == Key.Enter)
            {
                   AddTag(TagComboBox.Text);
                   //e.Handled = true;
                   //TagTextBox.Text = "";
               
                    //Keyboard.Focus(this);
                }
                else
                {
                    //sqlDataSet.SelectDistinctTagTable(TagComboBox.Text);
      
                }
                // PhotoSetComboBox.SelectedItem = new TextBlock(new Run(currentPhotoSetName));


            
        }


        

        #endregion


        #region TagText
        private void TagComboBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                AddTag(TagComboBox.Text);
                TagComboBox.Text = "";
                
                PhotoListBox.Focus();
                e.Handled = true;
            }
            
        }
        
        /*
        private void TagListBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                DataRowView drv = (DataRowView)TagListBox.SelectedItem;
                TagTextBox.Text = drv.Row[0].ToString();
                TagTextBox.Select(TagTextBox.Text.Length, 0);
                Keyboard.Focus(TagTextBox);
                e.Handled = true;
                TagTextBox.Focus();
               
            }
            if (e.Key == Key.Up)
            {

                if (TagListBox.SelectedIndex == 0)
                {
                    Keyboard.Focus(TagTextBox);
                    e.Handled = true;
                }

            }
        }

        private void TagTextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                AddTag(TagTextBox.Text);
                TagTextBox.Text = "";
                if (TagPopup.IsOpen == true)
                {
                    TagPopup.IsOpen = false;
                }
                PhotoListBox.Focus();
                e.Handled = true;
            }
            if (e.Key == Key.Up)
            {

                if (TagListBox.Items.Count > 0)
                {
                    TagListBox.Focus();
                    int selected = TagListBox.Items.Count - 1;
                    TagListBox.SelectedIndex = selected;
                }

            }
            if (e.Key == Key.Down)
            {

                if (TagListBox.Items.Count > 0)
                {
                    TagListBox.Focus();
                    TagListBox.SelectedIndex = 0;
                }

            }
        }

        public void TagTextBox_TextChanged(Object sender, TextChangedEventArgs e)
        {
            sqlDataSet.SelectDistinctTagTable(TagTextBox.Text);
        }

        void TagTextButton_Click(Object sender, RoutedEventArgs e)
        {
            if (TagPopup.IsOpen == false)
            {
                TagPopup.IsOpen = true;
            }
            TagTextBox.Focus();

        }
        */
        
        #endregion

        #region TagTreeView
        private void TagTreeViewAddAllButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                TreeViewItem item = (TreeViewItem)(sender as System.Windows.Controls.Button).TemplatedParent;
                AddTag(item.Header.ToString());
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Error with tag button: on remove" + ex.Message);
            }
        }
        private void TagTreeViewRemoveButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                TreeViewItem item = (TreeViewItem)(sender as System.Windows.Controls.Button).TemplatedParent;
                RemoveTag(item.Header.ToString());
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Error with tag button: on remove" + ex.Message);
            }
        }
        #endregion


        #region ButtonStars

        private void ButtonStars_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {

            ToggleButton starButton = (ToggleButton)sender;
            int pos = -1;


            for (int i = 0; i < 5; i++)
            {
                if (pos == -1)
                {
                    buttonStars[i].IsChecked = true;
                }
                else
                {
                    buttonStars[i].IsChecked = false;
                }
                if (buttonStars[i].Equals(starButton))
                {
                    pos = i;
                }
            }
        }


        private void ButtonStars_Update()
        {
            if (PhotoListBox.SelectedItems.Count == 1)
            {
                Photo photo = (Photo)PhotoListBox.SelectedItem;
                
                for (int i = 0; i < 5; i++)
                {
                    if (buttonStars[i] != null)
                    {
                        if (photo.Rating > i)
                        {
                            buttonStars[i].IsChecked = true;
                        }
                        else
                        {
                            buttonStars[i].IsChecked = false;
                        }
                    }
                }

            }
            else
            {
                for (int i = 0; i < 5; i++)
                {
                    buttonStars[i].IsChecked = false;
                }
            }

        }
        private void ButtonStars_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            ButtonStars_Update();
        }


        /// <summary>
        /// add Style to star buttons
        /// </summary>
        private void ButtonStars_AddStyle(ToggleButton btnStar)
        {
            Style starStyle = this.Resources["StarToggleButton"] as Style; ;
            if (starStyle != null)
            {
                btnStar.Style = starStyle;
                starStack.Children.Add(btnStar);
            }
        }



        /// <summary>
        /// 
        /// </summary>
        private void ButtonStars_Create()
        {
            starStack.Children.Clear();

            for (int i = 0; i < 5; i++)
            {
                buttonStars[i] = new ToggleButton();
                buttonStars[i].Width = 22;
                buttonStars[i].Height = 22;
                buttonStars[i].Click += new RoutedEventHandler(ButtonStars_Click);
                buttonStars[i].MouseEnter += new System.Windows.Input.MouseEventHandler(ButtonStars_MouseEnter);

                ButtonStars_AddStyle(buttonStars[i]);
            }

        }


        private void ButtonStars_Click(object sender, RoutedEventArgs e)
        {
            short rating = 0;
            ToggleButton starButton = (ToggleButton)sender;

            for (short i = 0; i < 5; i++)
            {
                if (buttonStars[i].Equals(starButton))
                {
                    buttonStars[i].IsChecked = true;
                }
                if (buttonStars[i].IsChecked.Value)
                {
                    rating++;
                }

            }
            AddRating(rating);
        }

        #endregion

        #region ExportPhoto
        private void ExportPhotoButton_Click(object sender, RoutedEventArgs e)
        {
            Collection<Photo> exportPhotos = new Collection<Photo>( PhotoListBox.SelectedItems.Cast<Photo>().ToList<Photo>());
            ExportDialog exportDialog = new ExportDialog(exportWorker, config, exportPhotos);// as Collection<Photo>) );
            exportDialog.ShowDialog();
            Configuration.Save("config.xml", config);
            
            
        }
        #endregion

        #region RotatePicture
        private void RotatePhoto(Rotation rotation)
        {
            foreach (Photo photo in PhotoListBox.SelectedItems)
            {
                PhotoFile p = new PhotoFile(photo.FullFilename, rotation);
                photo.Width = (int) p.width;
                photo.Height = (int)p.height;
                photo.Thumbnail = p.ThumbnailByteArray();
                Photo dbPhoto = photoEntities.Photos.FirstOrDefault(x => x.PhotoID == photo.PhotoID);
                dbPhoto.Width = (int)p.width;
                dbPhoto.Height = (int)p.height;
                dbPhoto.Thumbnail = p.ThumbnailByteArray();
                photoEntities.SaveChanges();
            }
           
        }
        private void RotateLeftButton_Click(object sender, RoutedEventArgs e)
        {
            RotatePhoto(Rotation.Rotate270);
        }
        private void RotateRightButton_Click(object sender, RoutedEventArgs e)
        {
            RotatePhoto(Rotation.Rotate90);
        }
#endregion
        private void AddMetaData(TextBox box)
        {
            
            foreach (Photo photo in PhotoListBox.SelectedItems)
            {
                
                switch (box.Name)
                {
                    case "CurrentSelectionCommentText":
                metaDataWorker.AddWork(photo.PhotoID, "Comment", box.Text);
                break;
                    case "CurrentSelectionTitleText":
                metaDataWorker.AddWork(photo.PhotoID, "Title", box.Text);
                break;
                    case "CurrentSelectionSubjectText":
                metaDataWorker.AddWork(photo.PhotoID, "Subject", box.Text);
                break;
            }
            }
        }

        private void MetaData_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            TextBox box = (TextBox)sender;
            string boxName = box.Name;
            if (e.Key == Key.Enter)
            {
                if (box.Text.Length > 0)
                {
                    AddMetaData(box);
                    Keyboard.Focus(PhotoListBox);
                }
            }
        }

        public void MetaData_LostKeyboardFocus(Object sender, KeyboardFocusChangedEventArgs e)
        {
            TextBox box = (TextBox)sender;
            string boxName = box.Name;

            if (box.Text.Length > 0)
            {
                AddMetaData(box);

            }

        }

        private void AddRating(short rating)
        {
            foreach (Photo photo in PhotoListBox.SelectedItems)
            {
                
                metaDataWorker.AddWork(photo.PhotoID, "Rating", rating);
                statusWorker.AddRatingUpdate("Adding " + rating + "stars");
            }

        }

        #region FunctionKeys

        private void FunctionKeyAddTag(object target, ExecutedRoutedEventArgs e)
        {
            string s = e.Parameter.ToString();
            AddTag(s);
        }

        private void BuildFunctionKeyInputBindings()
        {
            tagInputBindings[0] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F1));
            tagInputBindings[1] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F2));
            tagInputBindings[2] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F3));
            tagInputBindings[3] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F4));
            tagInputBindings[4] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F5));
            tagInputBindings[5] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F6));
            tagInputBindings[6] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F7));
            tagInputBindings[7] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F8));
            tagInputBindings[8] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F9));
            tagInputBindings[9] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F10));
            tagInputBindings[10] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F11));
            tagInputBindings[11] = new InputBinding(FunctionKeyAddTagCommand, new KeyGesture(Key.F12));
        }
        #endregion
    }
    #endregion
}
